home *** CD-ROM | disk | FTP | other *** search
/ PCMania 64 / PCMania CD64_1.iso / phy / phy002 / files / articulo.004 < prev    next >
Encoding:
Text File  |  1997-01-27  |  9.4 KB  |  164 lines

  1. *cN                Curso de programación orientada a objetos (II)
  2. *cG
  3.   En el anterior articulo nos quedamos a punto de ver que era la sobrecarga
  4. despues de dar nuestros primeros pasos en la filosofia de la OOP. Recordad
  5. los conceptos tratados pues será fundamental para poder seguir este y los
  6. siguientes artículos.
  7.   La sobrecarga es una potente técnica usada en los lenguajes POO para evitar
  8. los feos códigos fuente que se generan en los lenguajes tradicionales.
  9. Básicamente consiste en poder tener varias funciones con el mismo nombre
  10. dentro de un mismo programa. ¿Recordais en C cuando habia que usar nombres
  11. de funciones como *cOint_a_float()*cG, *cOstring_a_float()*cG, etc para convertir de
  12. un formato de datos a otro? Si lo que queremos es simplemente convertir de un
  13. tipo de dato dado a un float, ¿no seria más normal usar una función llamada
  14. *cOa_float()*cG para hacerlo?
  15.   C++ soluciona este problema con la sobrecarga y añade a esta filosofia un
  16. nuevo concepto que a mi personalmente me gusta mucho: la sobrecarga de
  17. operadores. Este concepto significa que eso mismo que hacemos con las funciones
  18. lo podemos hacer con los operadores (+, -, /, !, etc) y así podemos crear una
  19. clase para manejar números complejos y sobrecargar el operador de suma "+" y
  20. poder así sumar dos numeros complejos de la forma más natural que podriamos
  21. imaginar.
  22.   C++ como ya todos sabreis es un super-conjunto de C y por lo tanto se puede
  23. programar en C++ tal y como programariamos en C. Pero no se debe hacer ya que
  24. si lo hacemos perdemos todo lo que ganamos con la POO. Por tanto, si durante
  25. la série de artículos estais haciendo un programa y no sabeis como hacer algo
  26. en C++ podeis usar el C tradicional y luego pasarlo a C++ cuando sepais más.
  27.   Para definir una clase en C++ se suelen usar 2 ficheros (y es muy conveniente
  28. hacerlo): uno para definir la clase y otra con los métodos (funciones) que
  29. usará esa clase. Para definir la clase se puede hacer así:
  30. *cB
  31.   class nombre {        [ 1]
  32.     private:            [ 2]
  33.         dato_a_1;       [ 3]
  34.           ...           [ 4]
  35.         dato_a_n;       [ 5]
  36.     protected:          [ 6]
  37.         dato_b_1;       [ 7]
  38.           ...           [ 8]
  39.         dato_b_n;       [ 9]
  40.     public:             [10]
  41.         dato_c_1;       [11]
  42.           ...           [12]
  43.         dato_c_n;       [13]
  44.         };              [14]
  45. *cG
  46.   Primero (linea 1) ponemos nombre a la clase que vamos a definir y abrimos
  47. la llave que definirá la zona de definición de la clase. Podemos ver en las
  48. líneas 2, 6 y 10 las palabras clave *cOprotected*cG, *cOprivate*cG y *cOpublic*cG que
  49. definen por quien podrán ser 'vistos' los distintos miembros de la clase. Los
  50. miembros protected no podran modificarse ni utilizarse desde fuera de los
  51. miembros de la clase. Private es la opción por defecto, es decir, si metemos
  52. algún miembro justo después de escribir la llave de apertura este pertenecerá
  53. al tipo private. Por otra parte, los tipos private y protected sólo se
  54. diferencian cuando se heredan clases así que ya los veremos cuando veamos este
  55. tópico. El tipo public define los miembros visibles desde cualquier lugar de
  56. la aplicación.
  57.   En las líneas donde he escrito *cEdato_?_?*cG podriamos haber definido tanto un
  58. dato como un método (así se llaman las funciones en los lenguajes de OOP).
  59. Para que la cosa quede más clara ahí va la definición de una pequeña clase
  60. llamada *cEhormiga*cG que bien podria pertenecer a una aplicación de vida
  61. artificial:
  62. *cB
  63.   class Hormiga {                       [ 1]
  64.     private:                            [ 2]
  65.         int     posicionX;              [ 3]
  66.         int     posicionY;              [ 4]
  67.         int     reserva;                [ 5]
  68.     public:                             [ 6]
  69.         void  avanza(void);             [ 7]
  70.         void  avanza(int x, int y);     [ 8]
  71.         void  come(void);               [ 9]
  72.         void  refresca(void);           [10]
  73.         };                              [11]
  74. *cG
  75.   En el ejemplo se ven cosas bastantes interesantes. En la primera línea vemos
  76. el nombre de la clase y hay que hacer notar que es muy importante recordar que
  77. tanto C como C++ son *cOcase sensitive*cG, es decir, que no es lo mismo *cEHormiga*cG
  78. que *cEhormiga*cG. En la parte private hemos metido las variables y NO en la parte
  79. public, nunca en la parte public ya que en la POO no debemos ordenar las cosas
  80. sino "pedirlas" (ver artículo anterior). Podemos ver también una sobrecarga de
  81. funciones (líneas 7 y 8) así cuando usemos un objeto de la clase *cEHormiga*cG
  82. podremos escribir tanto *cOavanza();*cG como *cOavanza(1,-1);*cG siendo esto mucho más
  83. intuitivo de cara al programador.
  84.   Esta clase deberia ser "implementada" en otro fichero aunque hay gente que
  85. le tiene el mal habito de implementarla en el mismo fichero de definición
  86. (hay programadores que incluso lo meten todo en el main). Implementar la clase
  87. no es más que escribir el código de los métodos definidos e inicializar las
  88. variables de la clase. Las extensiones que se suelen usar para los ficheros
  89. de definición o cabecera son HPP o HH y para los de implementación CPP.
  90.   Los métodos se definen escribiendo el tipo de datos que devuelven, el nombre
  91. de la clase, 4 puntos :-) es decir un doble dos puntos (::), el nombre del
  92. método que vamos a definir y los parámetros de entrada. Como ejemplo vamos a
  93. definir los 4 métodos de la clase Hormiga:
  94. *cB
  95.   void Hormiga :: avanza(void)                          [ 1]
  96.    {                                                    [ 2]
  97.     posicionX += random(2);                             [ 3]
  98.     posicionY += random(2);                             [ 4]
  99.     }                                                   [ 5]
  100.                                                         [ 6]
  101.   void Hormiga :: avanza(int x, int y)                  [ 7]
  102.    {                                                    [ 8]
  103.     posicionX += x;                                     [ 9]
  104.     posicionY += y;                                     [10]
  105.     }                                                   [11]
  106.                                                         [12]
  107.   void Hormiga :: come(void)                            [13]
  108.    {                                                    [14]
  109.     if(campo.hay_comida(posicionX, posicionY))          [15]
  110.       reserva += campo.come(posicionX, posicionY);      [16]
  111.     }                                                   [17]
  112.                                                         [18]
  113.   void Hormiga :: refresca(void)                        [19]
  114.    {                                                    [20]
  115.     if(--reserva < 0)                                   [21]
  116.       printf("La hormiga se ha muerto de hambre");      [22]
  117.     campo.dibuja(this);                                 [23]
  118.     }                                                   [24]
  119. *cG
  120.   En este ejemplo hay mucho trigo que trillar... Para empezar en las líneas
  121. 1, 7, 13 y 19 podemos ver lo que estaba explicando antes de la definición de
  122. los métodos: *cOvoid clase :: metodo(dato_1, ..., dato_n)*cG. Observa lo simple
  123. que ha sido definir dos métodos distintos para hacer lo mismo y con el mismo
  124. nombre (líneas 1-5 y 7-11) aprovechando la potencia de la sobrecarga. Las dos
  125. primeras funciones simplemente actualizan un par de variables internas, NO
  126. modificables desde fuera de la clase Hormiga.
  127.   La función come (13-17) comprueba si en la parte del campo donde está situada
  128. hay algo para comerselo y si es así se lo come. Aquí hay un punto (y nunca
  129. mejor dicho) bastante importante que debemos abordar. Seguro que te ha
  130. resultado extraño el nombre de la función *cOcampo.hay_comida()*cG y la de comer
  131. *cOcampo.come()*cG. No se trata de un nuevo modo de nombrar los métodos en C++,
  132. sino que es la llamada a un método de un objeto. En efecto, cuando nosotros
  133. creamos una clase y un objeto de esa clase, para llamar a los métodos de la
  134. zona pública del objeto (de la clase) debemos usar el nombre del objeto (del
  135. objeto que no de la clase), un punto y el método que vamos a llamar (este
  136. proceso lo desarrollaremos en profundidad más adelante). Para entender mejor
  137. todo esto, vamos a definir un par de objetos Hormiga y vamos a usarlos:
  138. *cB
  139.   Hormiga Pepa;
  140.   Hormiga Clara, Sofia;
  141.  
  142.   Pepa.avanza();
  143.   Clara.come();
  144. *cG
  145. Supongo que queda claro como se definen objetos y se usan. No entraré en más
  146. detalles, simplemente debo hacer notar que aunque parezca que las clases no
  147. son más que estructuras de datos y funciones (bastante parecidas a las de C),
  148. esto no es cierto ya que las clases son algo más que ya iremos viendo.
  149.   Un pequeño punto negro que queda por explicar en el código es el extraño
  150. "this" que aparece en la línea 23. Simplemente se trata de un puntero que se
  151. define automáticamente al crear un objeto y que apunta a él mismo. Por cierto,
  152. hay un elemento que no corresponde al C++ y es esa llamada a *cOprintf()*cG que
  153. queda obsoleta con los nuevos mecanismo de la POO que explicaremos más
  154. adelante.
  155.   Con este interesante ejemplo abordado hoy ya se está capacitado para
  156. plantearse problemas más complejos como el de la heréncia, los métodos inline
  157. y los constructores y destructores que veremos en el próximo número junto a
  158. un tema no muy relacionado con la POO, pero muy interesante para los
  159. programadores en C++ que es la compilación separada y el uso de las directivas
  160. del compilador para crear un código más elegante.
  161. *cL
  162.                                                           Navi Dj.
  163.  
  164.